package cn.demoncat.util.http.entity;

import cn.demoncat.util.exception.RestRuntimeException;
import cn.demoncat.util.lang.CollectionUtil;
import cn.demoncat.util.lang.JsonUtil;
import cn.demoncat.util.lang.MapUtil;
import cn.demoncat.util.lang.StringUtil;
import cn.demoncat.util.lang.entity.Result;
import cn.demoncat.util.web.HeaderUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;

/**
 * HTTP 响应对象
 * 
 * @author 延晓磊
 *
 * @since 2019年10月13日
 */
public class HttpResponse {

	/**
	 * 请求地址
	 */
	private String url;
	/**
	 * 响应码（HTTP）
	 */
	private int status;
	/**
	 * 响应消息
	 */
	private String msg;
	/**
	 * 响应体
	 */
	private byte[] body;
	/**
	 * 响应头信息  {@link HeaderUtil}
	 */
	private Map<String, List<String>> headers;
	/**
	 * 响应内容类型
	 */
	private String contentType;

	/**
	 * 构建响应 - 未发送的
	 *
	 * @param url
	 *
	 * @return
	 */
	public static HttpResponse buildUnborn(String url){
		HttpResponse response = new HttpResponse();
		response.status = 100;
		response.msg = "请求未发送";
		response.url = url;
		return response;
	}
	
    /**
     * 是否成功：HTTP status = 200
     * 
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2019年10月13日
     */
	public boolean isSuccess() {
		return this.status == 200;
	}

	/**
	 * 是否重定向：HTTP status = 302
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public boolean isRedirect(){
		return this.status == 302;
	}

	/**
     * 检查是否成功：HTTP status != 200 时抛异常
     * 
     * @return HttpResponse 成功
     * @throws RestRuntimeException
     * 
     * @author 延晓磊
	 * @return 
     *
     * @since 2019年10月13日
     */
	public HttpResponse check() {
		if (!isSuccess()) {
			// 请求成功，但HTTP状态码非200时抛异常
			throw RestRuntimeException.httpError(StringUtil.logFormat("url= {}, status = {}, msg = {}", this.url, this.status, this.msg));
		}
		return this;
	}
	
	/**
     * 获取二进制流结果
     * 
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2019年10月13日
     */
    public byte[] asBinary() {
    	// 检查结果，返回成功响应体
    	return check().body;
    }
    
    /**
     * 获取字符串结果
     * 
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2019年10月13日
     */
    public String asString() {
    	return asString(null);
    }

	/**
	 * 获取字符串结果
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public String asString(Charset charset) {
		return StringUtil.getStr(asBinary(), charset);
	}

	/**
	 * 获取重定向地址（302）
	 *
	 * @return location 头
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public String asRedirect(){
    	if (!isRedirect()) {
			// 请求成功，但HTTP状态码非302时抛异常
			throw RestRuntimeException.httpError(StringUtil.logFormat("url= {}, status = {}, msg = {}", this.url, this.status, this.msg));
    	}
    	return getHeader("location");
	}

    /**
     * 获取对象结果
     * 
     * @param clazz		目标对象类型（通过JSON反序列化）
     * 
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2019年10月13日
     */
    public <T>T asBean(Class<T> clazz) {
    	return JsonUtil.parse(asString(), clazz);
	}

	/**
	 * 获取对象结果
	 *
	 * @param clazz		目标对象类型（通过JSON反序列化）
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public <T>T asBean(Class<T> clazz, Charset charset) {
		return JsonUtil.parse(asString(charset), clazz);
	}

	/**
	 * 获取对象结果
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public JSONObject asBean() {
		return JsonUtil.parseObject(asString());
	}

	/**
	 * 获取对象结果
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public JSONObject asBean(Charset charset) {
		return JsonUtil.parseObject(asString(charset));
	}

	/**
	 * 获取集合结果
	 *
	 * @param clazz		目标对象类型（通过JSON反序列化）
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public <T>List<T> asList(Class<T> clazz) {
		return JsonUtil.parseList(asString(), clazz);
	}

	/**
	 * 获取集合结果
	 *
	 * @param clazz		目标对象类型（通过JSON反序列化）
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public <T>List<T> asList(Class<T> clazz, Charset charset) {
		return JsonUtil.parseList(asString(charset), clazz);
	}

	/**
	 * 获取集合结果
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public JSONArray asList() {
		return JsonUtil.parseArray(asString());
	}

	/**
	 * 获取集合结果
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public JSONArray asList(Charset charset) {
		return JsonUtil.parseArray(asString(charset));
	}

    /**
     * 获取Result结果
     * 
     * @return 200 = Result.success，302 = Result.redirectTop(320)，* Exception
     * 
     * @author 延晓磊
     *
     * @since 2019年10月13日
     */
    public Result asResult() {
    	if (isRedirect()) {
    		// 302
			return Result.redirectTop(asRedirect());
    	}else{
    		// 200
			return Result.rest(Result.parseJson(asString()));
		}
    }

    /**
     * 获取请求地址
     * 
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2019年10月14日
     */
	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	/**
	 * 获取响应码（HTTP）
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月14日
	 */
	public int getStatus() {
		return status;
	}

	public void setStatus(int status) {
		this.status = status;
	}

	/**
	 * 获取响应消息
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月14日
	 */
	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public void setBody(byte[] body) {
		this.body = body;
	}

	/**
	 * 获取响应头信息
	 * 
	 * @return 全部头信息
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月14日
	 */
	public Map<String, List<String>> getHeaders() {
		return headers;
	}

	/**
	 * 获取响应头信息
	 * 
	 * @return 多个头信息
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月14日
	 */
	public List<String> getHeaders(String header) {
		return MapUtil.get(this.headers, header);
	}
	
	/**
	 * 获取响应头信息
	 * 
	 * @return 单个头信息
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月14日
	 */
	public String getHeader(String header) {
		return CollectionUtil.get(getHeaders(header), 0);
	}
	
	public void setHeaders(Map<String, List<String>> headers) {
		this.headers = headers;
	}

	/**
	 * 响应内容类型
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月14日
	 */
	public String getContentType() {
		return contentType;
	}

	public void setContentType(String contentType) {
		this.contentType = contentType;
	}

}
